if (!require(devtools)) install.packages("pacman")
pacman::p_load(rtemps, ggpubr, Rmisc, tidyverse, here, magrittr, patchwork,
               gghalves)
pilot_data <- read_csv(here("pilot_task", "meta_explore_pilot.csv")) %>%
  mutate(across(type, ~if_else(. == "add", "Addition", "Multiplication")),
         across(c(ends_with("rt"), "time_elapsed"), ~divide_by(., 1000)),
         across(accuracy, ~multiply_by(., 100))) %>%
  filter(math_rt < 75)
  
names(pilot_data) <- c(
  "Sub_ID", "Response", "Answer", "Task", "High_Num", "Low_Num", "Accuracy",
  "RT", "Difficulty", "Slider_RT", "Trial", "Time_Elapsed")
  
pilot_data_summarizer <- function (x) {
  pilot_data %>%
    group_by(!!!x) %>%
    summarise(across(c(Accuracy, RT, Difficulty), ~mean(., na.rm = TRUE)))
}

pilot_data_summarized <- pilot_data_summarizer(quos(Low_Num, High_Num, Task))

pilot_data_high_nums <- pilot_data_summarizer(quos(High_Num, Task))
plotter <- function(df, x, y, x_label, y_label, min_x, max_x, min_y, max_y,
                     label_nudge, y_seq_start, y_seq_end, y_seq_delta, geom) {
  ggplot(eval(sym(df)), aes(!!sym(x), !!sym(y), color = Task)) +
    geom +
    labs(title = paste0("Relationship between\n", x_label, " and ", y_label),
         subtitle = "as a function of the type of math problem",
         x = x_label,
         y = y_label) +
    stat_cor(aes(label = paste(..r.label.., sep = "~‘")),
             position = position_nudge(y = label_nudge),
             show.legend = FALSE) +
    theme_minimal() +
    scale_colour_manual(values = c("#0072B2", "#D55E00")) +
    coord_cartesian(xlim = c(min_x, max_x), ylim = c(min_y, max_y)) +
    scale_y_continuous(breaks=seq(y_seq_start, y_seq_end, y_seq_delta))
}

heat_plotter <- function(measure, measure_text, by_task_min, by_task_max,
                         by_task_midpoint, compared_min, compared_max,
                         compared_midpont, low_color, mid_color,
                         high_color) {
  
  heat_by_task <- function(task) {
    pilot_data_summarized %>%
      filter(Task == task) %>%
      ggplot(aes(High_Num, Low_Num, fill=!!sym(measure))) +
      geom_tile() +
      scale_fill_gradient2(low=low_color, mid=mid_color, high=high_color,
                           na.value = "#802835", midpoint = by_task_midpoint,
                           limits=c(by_task_min, by_task_max)) +
      labs(subtitle =paste(sym(measure_text), "for", task, "Task,\nby",
                           if_else(task == "Addition", 
                                   "Addends",
                                   "Multiplicands")),
           x = "", y = "")
  }
  
  heats_compared <- pilot_data_summarized %>%
    arrange(desc(Task)) %>%
    group_by(Low_Num, High_Num) %>%
    mutate(comparison = lead(!!sym(measure))) %>%
    filter(row_number() == 1) %>%
    mutate(`Mult - Add` = !!sym(measure) - comparison) %>%
    ggplot(aes(High_Num, Low_Num, fill=`Mult - Add`)) +
    geom_tile() +
    scale_fill_gradient2(low=low_color, mid=mid_color, high=high_color,
                         na.value = "#802835", midpoint = compared_midpont,
                         limits=c(compared_min, compared_max)) +
    scale_x_continuous(breaks=1:24) +
    theme(panel.grid.minor.x = element_blank()) +
    scale_y_continuous(breaks=seq(2, 24, 2)) +
    labs(title = paste("Multiplication", sym(measure_text), "\n- Addition",
                       sym(measure_text)),
         x = "", y = "")
  
  (c("Addition", "Multiplication") %>%
      map(heat_by_task) %>%
      reduce(`+`) + plot_layout(guides = 'collect') +
      theme(legend.position = "right")) %>%
    divide_by(heats_compared)
}

intra_diffs <- function(task, color_scheme, x1, x2, side_1){
  df <- filter(d, Task == task)
  rts <- pull(df, RT)
  cis <- CI(rts)[1] - CI(rts)[3]
  list(
    geom_point(data = df, color = color_scheme, size = 1.5, alpha = .6),
    geom_half_boxplot(data = df, position = position_nudge(x = x1),
                      side = "r", outlier.shape = NA, center = TRUE,
                      errorbar.draw = FALSE, width = .2, fill = color_scheme),
    geom_half_violin(data = df,position = position_nudge(x = x2 * .3),
                     side = side_1, fill = color_scheme),
    geom_point(data = df, aes(y = mean(rts)),
               position = position_nudge(x = x2 * .13), color = color_scheme,
               alpha = .6, size = 1.5),
    geom_errorbar(data = df, aes(y = mean(rts), ymin = mean(rts) - cis,
                                 ymax = mean(rts) + cis),
                  position = position_nudge(x2 * .13), color = color_scheme,
                  width = 0.05, size = 0.4, alpha = .5)
  )
}

aurora_plotter <- function(Task_Compare_1, Task_Compare_2, min_y, max_y) {
  
  Combo_RT_setup <- filter(pilot_data, Task == Task_Compare_1, Accuracy == 100)
  
  df_plot_3 <- Combo_RT_setup %>%
    group_by(Low_Num, High_Num) %>%
    summarise(across(RT, mean), .groups = "drop") %>%
    mutate(df_rank_absolute = dense_rank(desc(RT)),
           df_rank_percentile = percent_rank(RT))
  
  df_plot_3_setup <- left_join(Combo_RT_setup,
                               df_plot_3, by = c("Low_Num", "High_Num"))
  
  df_plot_3 %>%
    expand(nesting(Low_Num, High_Num, df_rank_absolute, RT, df_rank_percentile),
           next_rows = full_seq(min_y:max_y, 1)) %>%
    ungroup() %>%
    mutate(Correlation = pmap_dbl(., function(df_rank_absolute, next_rows, ...){
      
      tryCatch(
        {
          df_rank_low <- df_rank_absolute - next_rows
          df_rank_high <- df_rank_absolute
          
          data_split <- if (Task_Compare_1 == Task_Compare_2) {
            df_plot_3_setup %>%
              group_by(df_rank_absolute >= df_rank_low &
                         df_rank_absolute < df_rank_high) %>%
              group_split()
          } else {
            list(
              filter(df_plot_3_setup, df_rank_absolute >= df_rank_low,
                     df_rank_absolute < df_rank_high),
              pilot_data %>%
                filter(Task == Task_Compare_2, Accuracy == 100) %>%
                rename(RT.x = RT)
            )
          }
          
          ready_for_cor <-  data_split %>%
            map_df(function(z){
              z %>%
                group_by(Sub_ID) %>%
                summarise(RT_mean = mean(RT.x),
                          total_instances = n(),
                          .groups="drop") %>%
                mutate(rand_name = runif(1, min=0, max=10^9))
            }) %>%
            group_by(Sub_ID) %>%
            filter(min(total_instances) >= 3) %>%
            ungroup() %>%
            select(-total_instances) %>%
            pivot_wider(names_from = rand_name, values_from = RT_mean) %>%
            filter(across(everything(), ~ !is.na(.x)))
          
          cor(pull(ready_for_cor, 2),
              pull(ready_for_cor, 3))
        },
        error=function(e) {
          return(0)
        }
      )
    }
    )
    ) %>%
    ggplot(aes(df_rank_percentile, next_rows, fill= Correlation)) +
    geom_raster() +
    scale_fill_viridis_c(direction = 1, limits = c(-.2, 1)) +
    theme_minimal() +
    scale_x_continuous(breaks = seq(.1, .9, .1)) +
    scale_y_continuous(breaks = seq(min_y, max_y, 2)) +
    labs(title = paste(Task_Compare_1, "Problems that Best Predict",
                       if_else(Task_Compare_1 == Task_Compare_2, "the Others",
                               paste("All the", Task_Compare_2, "Problems"))),
         subtitle = paste("Correlation is participants' average RT on correct",
                          "trials",
                          if_else(Task_Compare_1 == Task_Compare_2,
                                  paste("among either combinations in the",
                                        "snippet or out of it"),
                                  paste(tolower(Task_Compare_2), "problems",
                                        "as predicted by a snippet of ",
                                        tolower(Task_Compare_1), "problems")),
                          "\nEach snippet is the", tolower(Task_Compare_1),
                          "combinations that are the xth easiest or one of the",
                          "next y-axis-value subsequently most difficult",
                          "combinations"),
         caption=paste("The hope of this plot is to see how well we could",
                       "glean a participant's threshold for difficulty if we",
                       "give them only a\nfew trials. Although the y-axis",
                       "discusses how well presenting from", min_y, "to",
                       max_y, "predict one's general performance, the y-axis",
                       "\nis a little misleading because only a quarter of all",
                       "number combinations were presented to each",
                       "participant. So if we did\nwant to use practice",
                       "trials as a sort of proxy, we might be able to use",
                       "even fewer than the values seen on the y-axis."),
         x = paste("A", if_else(Task_Compare_1 == "Multiplication",
                                "Multiplicand", "Addend"),
                   "Combination that is this", "Ranked-Percentage Easy among",
                   "All Combinations"),
         y = "This many of the Next Most Difficult Combinations")
}


plot_10_theme <- list(
  theme_minimal(),
  theme(
    axis.line=element_line(color="white"), 
    plot.title = element_text(color="white"),
    plot.background = element_rect(fill="#1e394a"),
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank(),
    panel.border=element_blank(),
    panel.background=element_blank(),
    axis.text.x=element_text(angle=0, color="white", size=16, vjust= 0.5),
    axis.text.y=element_text(angle=0, color="white", size=16), 
    strip.text=element_text(face="bold", size=22),
    axis.line.x = element_line(color="white", size = 0.5),
    axis.line.y = element_line(color="white", size = 0.5),
    axis.ticks = element_blank(),
    strip.text.y=element_text(color="white"),
    strip.background = element_rect(fill="#1e394a"),
    legend.position="none",
    axis.title = element_text(size=24, face="bold", color="white"),
    panel.spacing.x = unit(1.25,"lines"),
    panel.spacing.y = unit(1.75,"lines"))
)

Individual Differences

Multiplication Accuracy

You can tell here that there was quite a range in terms of how people fared in terms of multiplication accuracy during the task. The following analyses don’t exclude any participants if their overall multiplication accuracy was below a certain value, but perhaps we should decide on such a floor, since I wonder how much of bad accuracy is a reflection of ability vs. effort.

pilot_data %>%
  group_by(Sub_ID) %>%
  filter(Task == "Multiplication") %>%
  summarise(Performance = mean(Accuracy),
            Response_Time = mean(RT)) %>%
  ggplot(aes(Response_Time, Performance)) +
  geom_point(size = .5) +
  labs(title = paste("Individual Differences in Addition and Response Time",
                     "on Multiplication Problems"),
       caption = paste(n_distinct(pilot_data$Sub_ID), "participants"),
       x = "Response Time (seconds)",
       y = "Accuracy (as a percent of all mult. problems)") +
  theme_minimal()


Predictors

Relationship between Addition and Multiplication Response Times

This data is filtered just for correct trials, and it shows that while people were certainly faster for addition problems than multiplication problems, there was also a pretty close relationship between how fast someone was for addition as they were for multiplication.

d <- pilot_data %>%
  filter(Accuracy == 100) %>%
  group_by(Task, Sub_ID) %>%
  summarise(RT = mean(RT, na.rm = FALSE))

ggplot(d, aes(x = Task, y = RT)) +
  intra_diffs("Addition", "#0072B2", -.28, -1, "l") +
  intra_diffs("Multiplication", "#D55E00", .18, 1, "r") +
  geom_line(aes(group = Sub_ID), color = 'lightgray', alpha = .3) +
  labs(title = paste("Individual Differences in Correct Response Times for",
                     "Addition and Multiplication"),
       x = "Math Type",
       y = "Average Response Time (seconds)"
  ) +
  theme_minimal()


How Well Multiplication Problems Predict Response Time on the Other Multiplication Problems

The idea of this plot is to see whether we can predict an individual’s response time for most correct multiplication problems as a function of only a sampling of correct multiplication problems. The brightest colors show that the snippet that is most predictive of all the other multiplication problems is if we look at response times to the problems that, averaged across all participants, were in the 85th-95th percentile of easiness (so pretty difficult problems). The x-axis is the lowest percentile multiplication problem in the snippet, and the y-axis is how many multiplication problems should compose this snippet. It’s also worth noting that increasing a snippet’s span (i.e. at larger y values) doesn’t necessarily lead to it more accurately predicting the rest of the multiplication problems’ response times, and if anything is detrimental to the predictions. That’s not to say that more trials in a sample leads to worse predictions, but just that when adding more trials means widening the scope of how difficult the problems in the sample were, the predictions might be more diluted.

aurora_plotter("Multiplication", "Multiplication", 8, 20)


Homing in on a High-Fidelity Multiplication Predicting Snippet

Now that we know which multiplication problems best predict the other ones, we can zoom in on this correlation. Clearly there is a tight correlation between an individual’s average response time for correct multiplication problems that are vs. are not in the 85-95th range of easiness. Only participants who had at least 3 correct trials in the snippet were included.

pilot_data %>%
  filter(Task == "Multiplication", Accuracy == 100) %>%
  group_by(Low_Num, High_Num) %>%
  mutate(Combo_RT_mean = mean(RT)) %>%
  ungroup() %>%
  mutate(df_rank_percentile = percent_rank(Combo_RT_mean)) %>%
  group_by(Sub_ID,
           sweetspot = df_rank_percentile >= .85 & df_rank_percentile < .95) %>%
  summarise(across(RT, mean),
            total = n() ) %>%
  ungroup() %>%
  filter(total >= 3) %>%
  group_by(Sub_ID) %>%
  filter(n() > 1) %>%
  ungroup() %>%
  select(-total) %>%
  pivot_wider(names_from = sweetspot, values_from = RT) %>%
  magrittr::set_names(c("Sub_ID", "Full", "Sample")) %>%
  ggplot(aes(x=Sample, y=Full)) +
  geom_point() +
  geom_smooth() +
  stat_cor(aes(label = paste(..r.label.., sep = "~‘")),
           # position = position_nudge(y = RT),
           show.legend = FALSE) +
  labs(title = paste("How well the 85th-95th Easiest Multiplication Prbolems",
                     "Predict Response Time on the Other Problems"),
       x = "Response Time Among Snippet",
       y = "Response Time of the Other Mult. Combinations",
       caption = "Each dot is one participant") +
  theme_minimal()


How Well Addition Problems Predict Response Time on Multiplication Problems

This plot has the same logic to it as the other Northern-Lights-esque plot just above, except this time the multiplication snippets are actually predicting addition response times, not fellow multiplication problems. The area that’s most predictive in the plot above is almost the same as in this plot, but the predictions in this plot are (perhaps unsurprisingly) more muted.

aurora_plotter("Addition", "Multiplication", 8, 20)


aurora_plotter("Addition", "Addition", 8, 20)


aurora_plotter("Multiplication", "Addition", 8, 20)

LS0tCnRpdGxlOiAiTWV0YS1FeHBsb3JlIFBpbG90IERhdGEsIEV4YW1pbmVkIgpkYXRlOiAiTGFzdCB1cGRhdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtjc3MsIGVjaG89RkFMU0V9CmJvZHkgewogIGZvbnQtc2l6ZTogMS42cmVtOwogIHRleHQtYWxpZ246IGp1c3RpZnk7Cn0KCi50aXRsZSB7CiAgZm9udC1zaXplOiA0N3B4OwogIGNvbG9yOiBmaXJlYnJpY2s7Cn0KCmgxLGgyLGgzLGg0LGg1IHsKICB0ZXh0LWFsaWduOiBsZWZ0Owp9CmBgYAoKYGBge3IgcHJlZmVyZW5jZXMsIGVjaG89RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nPUZBTFNFLCBlcnJvcj1GQUxTRSwgbWVzc2FnZT1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hc3A9LjcsIGZpZy5kaW0gPSBjKDE2LCA3KSwgZGV2PSdzdmcnKQpgYGAKCmBgYHtyIGltcG9ydH0KaWYgKCFyZXF1aXJlKGRldnRvb2xzKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikKcGFjbWFuOjpwX2xvYWQocnRlbXBzLCBnZ3B1YnIsIFJtaXNjLCB0aWR5dmVyc2UsIGhlcmUsIG1hZ3JpdHRyLCBwYXRjaHdvcmssCiAgICAgICAgICAgICAgIGdnaGFsdmVzKQpgYGAKCmBgYHtyIHByZXBEYXRhfQpwaWxvdF9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoInBpbG90X3Rhc2siLCAibWV0YV9leHBsb3JlX3BpbG90LmNzdiIpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHR5cGUsIH5pZl9lbHNlKC4gPT0gImFkZCIsICJBZGRpdGlvbiIsICJNdWx0aXBsaWNhdGlvbiIpKSwKICAgICAgICAgYWNyb3NzKGMoZW5kc193aXRoKCJydCIpLCAidGltZV9lbGFwc2VkIiksIH5kaXZpZGVfYnkoLiwgMTAwMCkpLAogICAgICAgICBhY3Jvc3MoYWNjdXJhY3ksIH5tdWx0aXBseV9ieSguLCAxMDApKSkgJT4lCiAgZmlsdGVyKG1hdGhfcnQgPCA3NSkKICAKbmFtZXMocGlsb3RfZGF0YSkgPC0gYygKICAiU3ViX0lEIiwgIlJlc3BvbnNlIiwgIkFuc3dlciIsICJUYXNrIiwgIkhpZ2hfTnVtIiwgIkxvd19OdW0iLCAiQWNjdXJhY3kiLAogICJSVCIsICJEaWZmaWN1bHR5IiwgIlNsaWRlcl9SVCIsICJUcmlhbCIsICJUaW1lX0VsYXBzZWQiKQogIApwaWxvdF9kYXRhX3N1bW1hcml6ZXIgPC0gZnVuY3Rpb24gKHgpIHsKICBwaWxvdF9kYXRhICU+JQogICAgZ3JvdXBfYnkoISEheCkgJT4lCiAgICBzdW1tYXJpc2UoYWNyb3NzKGMoQWNjdXJhY3ksIFJULCBEaWZmaWN1bHR5KSwgfm1lYW4oLiwgbmEucm0gPSBUUlVFKSkpCn0KCnBpbG90X2RhdGFfc3VtbWFyaXplZCA8LSBwaWxvdF9kYXRhX3N1bW1hcml6ZXIocXVvcyhMb3dfTnVtLCBIaWdoX051bSwgVGFzaykpCgpwaWxvdF9kYXRhX2hpZ2hfbnVtcyA8LSBwaWxvdF9kYXRhX3N1bW1hcml6ZXIocXVvcyhIaWdoX051bSwgVGFzaykpCmBgYAoKCmBgYHtyIHBsb3RGdW5jdGlvbnN9CnBsb3R0ZXIgPC0gZnVuY3Rpb24oZGYsIHgsIHksIHhfbGFiZWwsIHlfbGFiZWwsIG1pbl94LCBtYXhfeCwgbWluX3ksIG1heF95LAogICAgICAgICAgICAgICAgICAgICBsYWJlbF9udWRnZSwgeV9zZXFfc3RhcnQsIHlfc2VxX2VuZCwgeV9zZXFfZGVsdGEsIGdlb20pIHsKICBnZ3Bsb3QoZXZhbChzeW0oZGYpKSwgYWVzKCEhc3ltKHgpLCAhIXN5bSh5KSwgY29sb3IgPSBUYXNrKSkgKwogICAgZ2VvbSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKCJSZWxhdGlvbnNoaXAgYmV0d2VlblxuIiwgeF9sYWJlbCwgIiBhbmQgIiwgeV9sYWJlbCksCiAgICAgICAgIHN1YnRpdGxlID0gImFzIGEgZnVuY3Rpb24gb2YgdGhlIHR5cGUgb2YgbWF0aCBwcm9ibGVtIiwKICAgICAgICAgeCA9IHhfbGFiZWwsCiAgICAgICAgIHkgPSB5X2xhYmVsKSArCiAgICBzdGF0X2NvcihhZXMobGFiZWwgPSBwYXN0ZSguLnIubGFiZWwuLiwgc2VwID0gIn7igJgiKSksCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHkgPSBsYWJlbF9udWRnZSksCiAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkgKwogICAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKG1pbl94LCBtYXhfeCksIHlsaW0gPSBjKG1pbl95LCBtYXhfeSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKHlfc2VxX3N0YXJ0LCB5X3NlcV9lbmQsIHlfc2VxX2RlbHRhKSkKfQoKaGVhdF9wbG90dGVyIDwtIGZ1bmN0aW9uKG1lYXN1cmUsIG1lYXN1cmVfdGV4dCwgYnlfdGFza19taW4sIGJ5X3Rhc2tfbWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgYnlfdGFza19taWRwb2ludCwgY29tcGFyZWRfbWluLCBjb21wYXJlZF9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJlZF9taWRwb250LCBsb3dfY29sb3IsIG1pZF9jb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hfY29sb3IpIHsKICAKICBoZWF0X2J5X3Rhc2sgPC0gZnVuY3Rpb24odGFzaykgewogICAgcGlsb3RfZGF0YV9zdW1tYXJpemVkICU+JQogICAgICBmaWx0ZXIoVGFzayA9PSB0YXNrKSAlPiUKICAgICAgZ2dwbG90KGFlcyhIaWdoX051bSwgTG93X051bSwgZmlsbD0hIXN5bShtZWFzdXJlKSkpICsKICAgICAgZ2VvbV90aWxlKCkgKwogICAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3c9bG93X2NvbG9yLCBtaWQ9bWlkX2NvbG9yLCBoaWdoPWhpZ2hfY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIiM4MDI4MzUiLCBtaWRwb2ludCA9IGJ5X3Rhc2tfbWlkcG9pbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz1jKGJ5X3Rhc2tfbWluLCBieV90YXNrX21heCkpICsKICAgICAgbGFicyhzdWJ0aXRsZSA9cGFzdGUoc3ltKG1lYXN1cmVfdGV4dCksICJmb3IiLCB0YXNrLCAiVGFzayxcbmJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSh0YXNrID09ICJBZGRpdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRlbmRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXVsdGlwbGljYW5kcyIpKSwKICAgICAgICAgICB4ID0gIiIsIHkgPSAiIikKICB9CiAgCiAgaGVhdHNfY29tcGFyZWQgPC0gcGlsb3RfZGF0YV9zdW1tYXJpemVkICU+JQogICAgYXJyYW5nZShkZXNjKFRhc2spKSAlPiUKICAgIGdyb3VwX2J5KExvd19OdW0sIEhpZ2hfTnVtKSAlPiUKICAgIG11dGF0ZShjb21wYXJpc29uID0gbGVhZCghIXN5bShtZWFzdXJlKSkpICU+JQogICAgZmlsdGVyKHJvd19udW1iZXIoKSA9PSAxKSAlPiUKICAgIG11dGF0ZShgTXVsdCAtIEFkZGAgPSAhIXN5bShtZWFzdXJlKSAtIGNvbXBhcmlzb24pICU+JQogICAgZ2dwbG90KGFlcyhIaWdoX051bSwgTG93X051bSwgZmlsbD1gTXVsdCAtIEFkZGApKSArCiAgICBnZW9tX3RpbGUoKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3c9bG93X2NvbG9yLCBtaWQ9bWlkX2NvbG9yLCBoaWdoPWhpZ2hfY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICIjODAyODM1IiwgbWlkcG9pbnQgPSBjb21wYXJlZF9taWRwb250LAogICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoY29tcGFyZWRfbWluLCBjb21wYXJlZF9tYXgpKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPTE6MjQpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMiwgMjQsIDIpKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIk11bHRpcGxpY2F0aW9uIiwgc3ltKG1lYXN1cmVfdGV4dCksICJcbi0gQWRkaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgIHN5bShtZWFzdXJlX3RleHQpKSwKICAgICAgICAgeCA9ICIiLCB5ID0gIiIpCiAgCiAgKGMoIkFkZGl0aW9uIiwgIk11bHRpcGxpY2F0aW9uIikgJT4lCiAgICAgIG1hcChoZWF0X2J5X3Rhc2spICU+JQogICAgICByZWR1Y2UoYCtgKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgKwogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSkgJT4lCiAgICBkaXZpZGVfYnkoaGVhdHNfY29tcGFyZWQpCn0KCmludHJhX2RpZmZzIDwtIGZ1bmN0aW9uKHRhc2ssIGNvbG9yX3NjaGVtZSwgeDEsIHgyLCBzaWRlXzEpewogIGRmIDwtIGZpbHRlcihkLCBUYXNrID09IHRhc2spCiAgcnRzIDwtIHB1bGwoZGYsIFJUKQogIGNpcyA8LSBDSShydHMpWzFdIC0gQ0kocnRzKVszXQogIGxpc3QoCiAgICBnZW9tX3BvaW50KGRhdGEgPSBkZiwgY29sb3IgPSBjb2xvcl9zY2hlbWUsIHNpemUgPSAxLjUsIGFscGhhID0gLjYpLAogICAgZ2VvbV9oYWxmX2JveHBsb3QoZGF0YSA9IGRmLCBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSB4MSksCiAgICAgICAgICAgICAgICAgICAgICBzaWRlID0gInIiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGNlbnRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBlcnJvcmJhci5kcmF3ID0gRkFMU0UsIHdpZHRoID0gLjIsIGZpbGwgPSBjb2xvcl9zY2hlbWUpLAogICAgZ2VvbV9oYWxmX3Zpb2xpbihkYXRhID0gZGYscG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0geDIgKiAuMyksCiAgICAgICAgICAgICAgICAgICAgIHNpZGUgPSBzaWRlXzEsIGZpbGwgPSBjb2xvcl9zY2hlbWUpLAogICAgZ2VvbV9wb2ludChkYXRhID0gZGYsIGFlcyh5ID0gbWVhbihydHMpKSwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0geDIgKiAuMTMpLCBjb2xvciA9IGNvbG9yX3NjaGVtZSwKICAgICAgICAgICAgICAgYWxwaGEgPSAuNiwgc2l6ZSA9IDEuNSksCiAgICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBkZiwgYWVzKHkgPSBtZWFuKHJ0cyksIHltaW4gPSBtZWFuKHJ0cykgLSBjaXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSBtZWFuKHJ0cykgKyBjaXMpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHgyICogLjEzKSwgY29sb3IgPSBjb2xvcl9zY2hlbWUsCiAgICAgICAgICAgICAgICAgIHdpZHRoID0gMC4wNSwgc2l6ZSA9IDAuNCwgYWxwaGEgPSAuNSkKICApCn0KCmF1cm9yYV9wbG90dGVyIDwtIGZ1bmN0aW9uKFRhc2tfQ29tcGFyZV8xLCBUYXNrX0NvbXBhcmVfMiwgbWluX3ksIG1heF95KSB7CiAgCiAgQ29tYm9fUlRfc2V0dXAgPC0gZmlsdGVyKHBpbG90X2RhdGEsIFRhc2sgPT0gVGFza19Db21wYXJlXzEsIEFjY3VyYWN5ID09IDEwMCkKICAKICBkZl9wbG90XzMgPC0gQ29tYm9fUlRfc2V0dXAgJT4lCiAgICBncm91cF9ieShMb3dfTnVtLCBIaWdoX051bSkgJT4lCiAgICBzdW1tYXJpc2UoYWNyb3NzKFJULCBtZWFuKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgICBtdXRhdGUoZGZfcmFua19hYnNvbHV0ZSA9IGRlbnNlX3JhbmsoZGVzYyhSVCkpLAogICAgICAgICAgIGRmX3JhbmtfcGVyY2VudGlsZSA9IHBlcmNlbnRfcmFuayhSVCkpCiAgCiAgZGZfcGxvdF8zX3NldHVwIDwtIGxlZnRfam9pbihDb21ib19SVF9zZXR1cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmX3Bsb3RfMywgYnkgPSBjKCJMb3dfTnVtIiwgIkhpZ2hfTnVtIikpCiAgCiAgZGZfcGxvdF8zICU+JQogICAgZXhwYW5kKG5lc3RpbmcoTG93X051bSwgSGlnaF9OdW0sIGRmX3JhbmtfYWJzb2x1dGUsIFJULCBkZl9yYW5rX3BlcmNlbnRpbGUpLAogICAgICAgICAgIG5leHRfcm93cyA9IGZ1bGxfc2VxKG1pbl95Om1heF95LCAxKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoQ29ycmVsYXRpb24gPSBwbWFwX2RibCguLCBmdW5jdGlvbihkZl9yYW5rX2Fic29sdXRlLCBuZXh0X3Jvd3MsIC4uLil7CiAgICAgIAogICAgICB0cnlDYXRjaCgKICAgICAgICB7CiAgICAgICAgICBkZl9yYW5rX2xvdyA8LSBkZl9yYW5rX2Fic29sdXRlIC0gbmV4dF9yb3dzCiAgICAgICAgICBkZl9yYW5rX2hpZ2ggPC0gZGZfcmFua19hYnNvbHV0ZQogICAgICAgICAgCiAgICAgICAgICBkYXRhX3NwbGl0IDwtIGlmIChUYXNrX0NvbXBhcmVfMSA9PSBUYXNrX0NvbXBhcmVfMikgewogICAgICAgICAgICBkZl9wbG90XzNfc2V0dXAgJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoZGZfcmFua19hYnNvbHV0ZSA+PSBkZl9yYW5rX2xvdyAmCiAgICAgICAgICAgICAgICAgICAgICAgICBkZl9yYW5rX2Fic29sdXRlIDwgZGZfcmFua19oaWdoKSAlPiUKICAgICAgICAgICAgICBncm91cF9zcGxpdCgpCiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgIGZpbHRlcihkZl9wbG90XzNfc2V0dXAsIGRmX3JhbmtfYWJzb2x1dGUgPj0gZGZfcmFua19sb3csCiAgICAgICAgICAgICAgICAgICAgIGRmX3JhbmtfYWJzb2x1dGUgPCBkZl9yYW5rX2hpZ2gpLAogICAgICAgICAgICAgIHBpbG90X2RhdGEgJT4lCiAgICAgICAgICAgICAgICBmaWx0ZXIoVGFzayA9PSBUYXNrX0NvbXBhcmVfMiwgQWNjdXJhY3kgPT0gMTAwKSAlPiUKICAgICAgICAgICAgICAgIHJlbmFtZShSVC54ID0gUlQpCiAgICAgICAgICAgICkKICAgICAgICAgIH0KICAgICAgICAgIAogICAgICAgICAgcmVhZHlfZm9yX2NvciA8LSAgZGF0YV9zcGxpdCAlPiUKICAgICAgICAgICAgbWFwX2RmKGZ1bmN0aW9uKHopewogICAgICAgICAgICAgIHogJT4lCiAgICAgICAgICAgICAgICBncm91cF9ieShTdWJfSUQpICU+JQogICAgICAgICAgICAgICAgc3VtbWFyaXNlKFJUX21lYW4gPSBtZWFuKFJULngpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2luc3RhbmNlcyA9IG4oKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAuZ3JvdXBzPSJkcm9wIikgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUocmFuZF9uYW1lID0gcnVuaWYoMSwgbWluPTAsIG1heD0xMF45KSkKICAgICAgICAgICAgfSkgJT4lCiAgICAgICAgICAgIGdyb3VwX2J5KFN1Yl9JRCkgJT4lCiAgICAgICAgICAgIGZpbHRlcihtaW4odG90YWxfaW5zdGFuY2VzKSA+PSAzKSAlPiUKICAgICAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgICAgICBzZWxlY3QoLXRvdGFsX2luc3RhbmNlcykgJT4lCiAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByYW5kX25hbWUsIHZhbHVlc19mcm9tID0gUlRfbWVhbikgJT4lCiAgICAgICAgICAgIGZpbHRlcihhY3Jvc3MoZXZlcnl0aGluZygpLCB+ICFpcy5uYSgueCkpKQogICAgICAgICAgCiAgICAgICAgICBjb3IocHVsbChyZWFkeV9mb3JfY29yLCAyKSwKICAgICAgICAgICAgICBwdWxsKHJlYWR5X2Zvcl9jb3IsIDMpKQogICAgICAgIH0sCiAgICAgICAgZXJyb3I9ZnVuY3Rpb24oZSkgewogICAgICAgICAgcmV0dXJuKDApCiAgICAgICAgfQogICAgICApCiAgICB9CiAgICApCiAgICApICU+JQogICAgZ2dwbG90KGFlcyhkZl9yYW5rX3BlcmNlbnRpbGUsIG5leHRfcm93cywgZmlsbD0gQ29ycmVsYXRpb24pKSArCiAgICBnZW9tX3Jhc3RlcigpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGRpcmVjdGlvbiA9IDEsIGxpbWl0cyA9IGMoLS4yLCAxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoLjEsIC45LCAuMSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEobWluX3ksIG1heF95LCAyKSkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlKFRhc2tfQ29tcGFyZV8xLCAiUHJvYmxlbXMgdGhhdCBCZXN0IFByZWRpY3QiLAogICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoVGFza19Db21wYXJlXzEgPT0gVGFza19Db21wYXJlXzIsICJ0aGUgT3RoZXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJBbGwgdGhlIiwgVGFza19Db21wYXJlXzIsICJQcm9ibGVtcyIpKSksCiAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkNvcnJlbGF0aW9uIGlzIHBhcnRpY2lwYW50cycgYXZlcmFnZSBSVCBvbiBjb3JyZWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAidHJpYWxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKFRhc2tfQ29tcGFyZV8xID09IFRhc2tfQ29tcGFyZV8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoImFtb25nIGVpdGhlciBjb21iaW5hdGlvbnMgaW4gdGhlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzbmlwcGV0IG9yIG91dCBvZiBpdCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUodG9sb3dlcihUYXNrX0NvbXBhcmVfMiksICJwcm9ibGVtcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYXMgcHJlZGljdGVkIGJ5IGEgc25pcHBldCBvZiAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9sb3dlcihUYXNrX0NvbXBhcmVfMSksICJwcm9ibGVtcyIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5FYWNoIHNuaXBwZXQgaXMgdGhlIiwgdG9sb3dlcihUYXNrX0NvbXBhcmVfMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbWJpbmF0aW9ucyB0aGF0IGFyZSB0aGUgeHRoIGVhc2llc3Qgb3Igb25lIG9mIHRoZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIm5leHQgeS1heGlzLXZhbHVlIHN1YnNlcXVlbnRseSBtb3N0IGRpZmZpY3VsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbWJpbmF0aW9ucyIpLAogICAgICAgICBjYXB0aW9uPXBhc3RlKCJUaGUgaG9wZSBvZiB0aGlzIHBsb3QgaXMgdG8gc2VlIGhvdyB3ZWxsIHdlIGNvdWxkIiwKICAgICAgICAgICAgICAgICAgICAgICAiZ2xlYW4gYSBwYXJ0aWNpcGFudCdzIHRocmVzaG9sZCBmb3IgZGlmZmljdWx0eSBpZiB3ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgImdpdmUgdGhlbSBvbmx5IGFcbmZldyB0cmlhbHMuIEFsdGhvdWdoIHRoZSB5LWF4aXMiLAogICAgICAgICAgICAgICAgICAgICAgICJkaXNjdXNzZXMgaG93IHdlbGwgcHJlc2VudGluZyBmcm9tIiwgbWluX3ksICJ0byIsCiAgICAgICAgICAgICAgICAgICAgICAgbWF4X3ksICJwcmVkaWN0IG9uZSdzIGdlbmVyYWwgcGVyZm9ybWFuY2UsIHRoZSB5LWF4aXMiLAogICAgICAgICAgICAgICAgICAgICAgICJcbmlzIGEgbGl0dGxlIG1pc2xlYWRpbmcgYmVjYXVzZSBvbmx5IGEgcXVhcnRlciBvZiBhbGwiLAogICAgICAgICAgICAgICAgICAgICAgICJudW1iZXIgY29tYmluYXRpb25zIHdlcmUgcHJlc2VudGVkIHRvIGVhY2giLAogICAgICAgICAgICAgICAgICAgICAgICJwYXJ0aWNpcGFudC4gU28gaWYgd2UgZGlkXG53YW50IHRvIHVzZSBwcmFjdGljZSIsCiAgICAgICAgICAgICAgICAgICAgICAgInRyaWFscyBhcyBhIHNvcnQgb2YgcHJveHksIHdlIG1pZ2h0IGJlIGFibGUgdG8gdXNlIiwKICAgICAgICAgICAgICAgICAgICAgICAiZXZlbiBmZXdlciB0aGFuIHRoZSB2YWx1ZXMgc2VlbiBvbiB0aGUgeS1heGlzLiIpLAogICAgICAgICB4ID0gcGFzdGUoIkEiLCBpZl9lbHNlKFRhc2tfQ29tcGFyZV8xID09ICJNdWx0aXBsaWNhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk11bHRpcGxpY2FuZCIsICJBZGRlbmQiKSwKICAgICAgICAgICAgICAgICAgICJDb21iaW5hdGlvbiB0aGF0IGlzIHRoaXMiLCAiUmFua2VkLVBlcmNlbnRhZ2UgRWFzeSBhbW9uZyIsCiAgICAgICAgICAgICAgICAgICAiQWxsIENvbWJpbmF0aW9ucyIpLAogICAgICAgICB5ID0gIlRoaXMgbWFueSBvZiB0aGUgTmV4dCBNb3N0IERpZmZpY3VsdCBDb21iaW5hdGlvbnMiKQp9CgoKcGxvdF8xMF90aGVtZSA8LSBsaXN0KAogIHRoZW1lX21pbmltYWwoKSwKICB0aGVtZSgKICAgIGF4aXMubGluZT1lbGVtZW50X2xpbmUoY29sb3I9IndoaXRlIiksIAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvcj0id2hpdGUiKSwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSIjMWUzOTRhIiksCiAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTAsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9MTYsIHZqdXN0PSAwLjUpLAogICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KGFuZ2xlPTAsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9MTYpLCAKICAgIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBzaXplPTIyKSwKICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9saW5lKGNvbG9yPSJ3aGl0ZSIsIHNpemUgPSAwLjUpLAogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3I9IndoaXRlIiwgc2l6ZSA9IDAuNSksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvcj0id2hpdGUiKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0iIzFlMzk0YSIpLAogICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yNCwgZmFjZT0iYm9sZCIsIGNvbG9yPSJ3aGl0ZSIpLAogICAgcGFuZWwuc3BhY2luZy54ID0gdW5pdCgxLjI1LCJsaW5lcyIpLAogICAgcGFuZWwuc3BhY2luZy55ID0gdW5pdCgxLjc1LCJsaW5lcyIpKQopCmBgYAoKIyBJbmRpdmlkdWFsIERpZmZlcmVuY2VzIHstfQoKIyMgIE11bHRpcGxpY2F0aW9uIEFjY3VyYWN5IHstfQoKWW91IGNhbiB0ZWxsIGhlcmUgdGhhdCB0aGVyZSB3YXMgcXVpdGUgYSByYW5nZSBpbiB0ZXJtcyBvZiBob3cgcGVvcGxlIGZhcmVkIGluIHRlcm1zIG9mIG11bHRpcGxpY2F0aW9uIGFjY3VyYWN5IGR1cmluZyB0aGUgdGFzay4gVGhlIGZvbGxvd2luZyBhbmFseXNlcyBkb24ndCBleGNsdWRlIGFueSBwYXJ0aWNpcGFudHMgaWYgdGhlaXIgb3ZlcmFsbCBtdWx0aXBsaWNhdGlvbiBhY2N1cmFjeSB3YXMgYmVsb3cgYSBjZXJ0YWluIHZhbHVlLCBidXQgcGVyaGFwcyB3ZSBzaG91bGQgZGVjaWRlIG9uIHN1Y2ggYSBmbG9vciwgc2luY2UgSSB3b25kZXIgaG93IG11Y2ggb2YgYmFkIGFjY3VyYWN5IGlzIGEgcmVmbGVjdGlvbiBvZiBhYmlsaXR5IHZzLiBlZmZvcnQuCgpgYGB7ciBwbG90MX0KcGlsb3RfZGF0YSAlPiUKICBncm91cF9ieShTdWJfSUQpICU+JQogIGZpbHRlcihUYXNrID09ICJNdWx0aXBsaWNhdGlvbiIpICU+JQogIHN1bW1hcmlzZShQZXJmb3JtYW5jZSA9IG1lYW4oQWNjdXJhY3kpLAogICAgICAgICAgICBSZXNwb25zZV9UaW1lID0gbWVhbihSVCkpICU+JQogIGdncGxvdChhZXMoUmVzcG9uc2VfVGltZSwgUGVyZm9ybWFuY2UpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIkluZGl2aWR1YWwgRGlmZmVyZW5jZXMgaW4gQWRkaXRpb24gYW5kIFJlc3BvbnNlIFRpbWUiLAogICAgICAgICAgICAgICAgICAgICAib24gTXVsdGlwbGljYXRpb24gUHJvYmxlbXMiKSwKICAgICAgIGNhcHRpb24gPSBwYXN0ZShuX2Rpc3RpbmN0KHBpbG90X2RhdGEkU3ViX0lEKSwgInBhcnRpY2lwYW50cyIpLAogICAgICAgeCA9ICJSZXNwb25zZSBUaW1lIChzZWNvbmRzKSIsCiAgICAgICB5ID0gIkFjY3VyYWN5IChhcyBhIHBlcmNlbnQgb2YgYWxsIG11bHQuIHByb2JsZW1zKSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgotLS0tCgojIyBQcmVkaWN0b3JzIHstfQoKIyMjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIEFkZGl0aW9uIGFuZCBNdWx0aXBsaWNhdGlvbiBSZXNwb25zZSBUaW1lcyB7LX0KClRoaXMgZGF0YSBpcyBmaWx0ZXJlZCBqdXN0IGZvciBjb3JyZWN0IHRyaWFscywgYW5kIGl0IHNob3dzIHRoYXQgd2hpbGUgcGVvcGxlIHdlcmUgY2VydGFpbmx5IGZhc3RlciBmb3IgYWRkaXRpb24gcHJvYmxlbXMgdGhhbiBtdWx0aXBsaWNhdGlvbiBwcm9ibGVtcywgdGhlcmUgd2FzIGFsc28gYSBwcmV0dHkgY2xvc2UgcmVsYXRpb25zaGlwIGJldHdlZW4gaG93IGZhc3Qgc29tZW9uZSB3YXMgZm9yIGFkZGl0aW9uIGFzIHRoZXkgd2VyZSBmb3IgbXVsdGlwbGljYXRpb24uCgpgYGB7ciBwbG90Mn0KZCA8LSBwaWxvdF9kYXRhICU+JQogIGZpbHRlcihBY2N1cmFjeSA9PSAxMDApICU+JQogIGdyb3VwX2J5KFRhc2ssIFN1Yl9JRCkgJT4lCiAgc3VtbWFyaXNlKFJUID0gbWVhbihSVCwgbmEucm0gPSBGQUxTRSkpCgpnZ3Bsb3QoZCwgYWVzKHggPSBUYXNrLCB5ID0gUlQpKSArCiAgaW50cmFfZGlmZnMoIkFkZGl0aW9uIiwgIiMwMDcyQjIiLCAtLjI4LCAtMSwgImwiKSArCiAgaW50cmFfZGlmZnMoIk11bHRpcGxpY2F0aW9uIiwgIiNENTVFMDAiLCAuMTgsIDEsICJyIikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBTdWJfSUQpLCBjb2xvciA9ICdsaWdodGdyYXknLCBhbHBoYSA9IC4zKSArCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJJbmRpdmlkdWFsIERpZmZlcmVuY2VzIGluIENvcnJlY3QgUmVzcG9uc2UgVGltZXMgZm9yIiwKICAgICAgICAgICAgICAgICAgICAgIkFkZGl0aW9uIGFuZCBNdWx0aXBsaWNhdGlvbiIpLAogICAgICAgeCA9ICJNYXRoIFR5cGUiLAogICAgICAgeSA9ICJBdmVyYWdlIFJlc3BvbnNlIFRpbWUgKHNlY29uZHMpIgogICkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCi0tLS0KCiMjIyBIb3cgV2VsbCBNdWx0aXBsaWNhdGlvbiBQcm9ibGVtcyBQcmVkaWN0IFJlc3BvbnNlIFRpbWUgb24gdGhlIE90aGVyIE11bHRpcGxpY2F0aW9uIFByb2JsZW1zIHstfQoKVGhlIGlkZWEgb2YgdGhpcyBwbG90IGlzIHRvIHNlZSB3aGV0aGVyIHdlIGNhbiBwcmVkaWN0IGFuIGluZGl2aWR1YWwncyByZXNwb25zZSB0aW1lIGZvciBtb3N0IGNvcnJlY3QgbXVsdGlwbGljYXRpb24gcHJvYmxlbXMgYXMgYSBmdW5jdGlvbiBvZiBvbmx5IGEgc2FtcGxpbmcgb2YgY29ycmVjdCBtdWx0aXBsaWNhdGlvbiBwcm9ibGVtcy4gVGhlIGJyaWdodGVzdCBjb2xvcnMgc2hvdyB0aGF0IHRoZSBzbmlwcGV0IHRoYXQgaXMgbW9zdCBwcmVkaWN0aXZlIG9mIGFsbCB0aGUgb3RoZXIgbXVsdGlwbGljYXRpb24gcHJvYmxlbXMgaXMgaWYgd2UgbG9vayBhdCByZXNwb25zZSB0aW1lcyB0byB0aGUgcHJvYmxlbXMgdGhhdCwgYXZlcmFnZWQgYWNyb3NzIGFsbCBwYXJ0aWNpcGFudHMsIHdlcmUgaW4gdGhlIDg1dGgtOTV0aCBwZXJjZW50aWxlIG9mIGVhc2luZXNzIChzbyBwcmV0dHkgZGlmZmljdWx0IHByb2JsZW1zKS4gVGhlIHgtYXhpcyBpcyB0aGUgbG93ZXN0IHBlcmNlbnRpbGUgbXVsdGlwbGljYXRpb24gcHJvYmxlbSBpbiB0aGUgc25pcHBldCwgYW5kIHRoZSB5LWF4aXMgaXMgaG93IG1hbnkgbXVsdGlwbGljYXRpb24gcHJvYmxlbXMgc2hvdWxkIGNvbXBvc2UgdGhpcyBzbmlwcGV0LiBJdCdzIGFsc28gd29ydGggbm90aW5nIHRoYXQgaW5jcmVhc2luZyBhIHNuaXBwZXQncyBzcGFuIChpLmUuIGF0IGxhcmdlciB5IHZhbHVlcykgZG9lc24ndCBuZWNlc3NhcmlseSBsZWFkIHRvIGl0IG1vcmUgYWNjdXJhdGVseSBwcmVkaWN0aW5nIHRoZSByZXN0IG9mIHRoZSBtdWx0aXBsaWNhdGlvbiBwcm9ibGVtcycgcmVzcG9uc2UgdGltZXMsIGFuZCBpZiBhbnl0aGluZyBpcyBkZXRyaW1lbnRhbCB0byB0aGUgcHJlZGljdGlvbnMuIFRoYXQncyBub3QgdG8gc2F5IHRoYXQgbW9yZSB0cmlhbHMgaW4gYSBzYW1wbGUgbGVhZHMgdG8gd29yc2UgcHJlZGljdGlvbnMsIGJ1dCBqdXN0IHRoYXQgd2hlbiBhZGRpbmcgbW9yZSB0cmlhbHMgbWVhbnMgd2lkZW5pbmcgdGhlIHNjb3BlIG9mIGhvdyBkaWZmaWN1bHQgdGhlIHByb2JsZW1zIGluIHRoZSBzYW1wbGUgd2VyZSwgdGhlIHByZWRpY3Rpb25zIG1pZ2h0IGJlIG1vcmUgZGlsdXRlZC4KCmBgYHtyIHBsb3QzfQphdXJvcmFfcGxvdHRlcigiTXVsdGlwbGljYXRpb24iLCAiTXVsdGlwbGljYXRpb24iLCA4LCAyMCkKYGBgCgotLS0tCgojIyMgSG9taW5nIGluIG9uIGEgSGlnaC1GaWRlbGl0eSBNdWx0aXBsaWNhdGlvbiBQcmVkaWN0aW5nIFNuaXBwZXR7LX0KCk5vdyB0aGF0IHdlIGtub3cgd2hpY2ggbXVsdGlwbGljYXRpb24gcHJvYmxlbXMgYmVzdCBwcmVkaWN0IHRoZSBvdGhlciBvbmVzLCB3ZSBjYW4gem9vbSBpbiBvbiB0aGlzIGNvcnJlbGF0aW9uLiBDbGVhcmx5IHRoZXJlIGlzIGEgdGlnaHQgY29ycmVsYXRpb24gYmV0d2VlbiBhbiBpbmRpdmlkdWFsJ3MgYXZlcmFnZSByZXNwb25zZSB0aW1lIGZvciBjb3JyZWN0IG11bHRpcGxpY2F0aW9uIHByb2JsZW1zIHRoYXQgYXJlIHZzLiBhcmUgbm90IGluIHRoZSA4NS05NXRoIHJhbmdlIG9mIGVhc2luZXNzLiBPbmx5IHBhcnRpY2lwYW50cyB3aG8gaGFkIGF0IGxlYXN0IDMgY29ycmVjdCB0cmlhbHMgaW4gdGhlIHNuaXBwZXQgd2VyZSBpbmNsdWRlZC4KCmBgYHtyLCBwbG90NH0KcGlsb3RfZGF0YSAlPiUKICBmaWx0ZXIoVGFzayA9PSAiTXVsdGlwbGljYXRpb24iLCBBY2N1cmFjeSA9PSAxMDApICU+JQogIGdyb3VwX2J5KExvd19OdW0sIEhpZ2hfTnVtKSAlPiUKICBtdXRhdGUoQ29tYm9fUlRfbWVhbiA9IG1lYW4oUlQpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGRmX3JhbmtfcGVyY2VudGlsZSA9IHBlcmNlbnRfcmFuayhDb21ib19SVF9tZWFuKSkgJT4lCiAgZ3JvdXBfYnkoU3ViX0lELAogICAgICAgICAgIHN3ZWV0c3BvdCA9IGRmX3JhbmtfcGVyY2VudGlsZSA+PSAuODUgJiBkZl9yYW5rX3BlcmNlbnRpbGUgPCAuOTUpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoUlQsIG1lYW4pLAogICAgICAgICAgICB0b3RhbCA9IG4oKSApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIodG90YWwgPj0gMykgJT4lCiAgZ3JvdXBfYnkoU3ViX0lEKSAlPiUKICBmaWx0ZXIobigpID4gMSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtdG90YWwpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzd2VldHNwb3QsIHZhbHVlc19mcm9tID0gUlQpICU+JQogIG1hZ3JpdHRyOjpzZXRfbmFtZXMoYygiU3ViX0lEIiwgIkZ1bGwiLCAiU2FtcGxlIikpICU+JQogIGdncGxvdChhZXMoeD1TYW1wbGUsIHk9RnVsbCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkgKwogIHN0YXRfY29yKGFlcyhsYWJlbCA9IHBhc3RlKC4uci5sYWJlbC4uLCBzZXAgPSAifuKAmCIpKSwKICAgICAgICAgICAjIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeSA9IFJUKSwKICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJIb3cgd2VsbCB0aGUgODV0aC05NXRoIEVhc2llc3QgTXVsdGlwbGljYXRpb24gUHJib2xlbXMiLAogICAgICAgICAgICAgICAgICAgICAiUHJlZGljdCBSZXNwb25zZSBUaW1lIG9uIHRoZSBPdGhlciBQcm9ibGVtcyIpLAogICAgICAgeCA9ICJSZXNwb25zZSBUaW1lIEFtb25nIFNuaXBwZXQiLAogICAgICAgeSA9ICJSZXNwb25zZSBUaW1lIG9mIHRoZSBPdGhlciBNdWx0LiBDb21iaW5hdGlvbnMiLAogICAgICAgY2FwdGlvbiA9ICJFYWNoIGRvdCBpcyBvbmUgcGFydGljaXBhbnQiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKLS0tLQoKIyMjIEhvdyBXZWxsIEFkZGl0aW9uIFByb2JsZW1zIFByZWRpY3QgUmVzcG9uc2UgVGltZSBvbiBNdWx0aXBsaWNhdGlvbiBQcm9ibGVtcyB7LX0KClRoaXMgcGxvdCBoYXMgdGhlIHNhbWUgbG9naWMgdG8gaXQgYXMgdGhlIG90aGVyIE5vcnRoZXJuLUxpZ2h0cy1lc3F1ZSBwbG90IGp1c3QgYWJvdmUsIGV4Y2VwdCB0aGlzIHRpbWUgdGhlIG11bHRpcGxpY2F0aW9uIHNuaXBwZXRzIGFyZSBhY3R1YWxseSBwcmVkaWN0aW5nIGFkZGl0aW9uIHJlc3BvbnNlIHRpbWVzLCBub3QgZmVsbG93IG11bHRpcGxpY2F0aW9uIHByb2JsZW1zLiBUaGUgYXJlYSB0aGF0J3MgbW9zdCBwcmVkaWN0aXZlIGluIHRoZSBwbG90IGFib3ZlIGlzIGFsbW9zdCB0aGUgc2FtZSBhcyBpbiB0aGlzIHBsb3QsIGJ1dCB0aGUgcHJlZGljdGlvbnMgaW4gdGhpcyBwbG90IGFyZSAocGVyaGFwcyB1bnN1cnByaXNpbmdseSkgbW9yZSBtdXRlZC4KCmBgYHtyIHBsb3Q1fQphdXJvcmFfcGxvdHRlcigiQWRkaXRpb24iLCAiTXVsdGlwbGljYXRpb24iLCA4LCAyMCkKYGBgCgotLS0KCmBgYHtyIHBsb3Q2fQphdXJvcmFfcGxvdHRlcigiQWRkaXRpb24iLCAiQWRkaXRpb24iLCA4LCAyMCkKYGBgCgotLS0KCmBgYHtyIHBsb3Q3fQphdXJvcmFfcGxvdHRlcigiTXVsdGlwbGljYXRpb24iLCAiQWRkaXRpb24iLCA4LCAyMCkKYGBgCgoKIyBUcmVuZHMgQWNyb3NzIFBhcnRpY2lwYW50cyB7LX0KCiMjIFJlbGF0aW9uc2hpcHMgYi93IERlcGVuZGVudCBWcyB7LX0KCiMjIyBTY2F0dGVycGxvdCBvZiBUcmlhbC1ieS1UcmlhbCBSZWxhdGlvbnNoaXAgYmV0d2VlbiBEaWZmaWN1bHR5IFJhdGluZyBhbmQgUmVzcG9uc2UgVGltZSB7LX0KCk9ubHkgY29ycmVjdCB0cmlhbHMgYXJlIHBsb3R0ZWQsIGFuZCBldmVuIHRob3VnaCBtb3N0IG9mIHRoZSB0cmlhbHMgbGFzdCBsZXNzIHRoYW4gMTAgc2Vjb25kcywgdGhlcmUgaXMgY2VydGFpbmx5IHNvbWUgdmFyaWFiaWxpdHksIGFsbW9zdCBhbGwgb2Ygd2hpY2ggaXMgZHJpdmVuIGJ5IG11bHRpcGxpY2F0aW9uIHByb2JsZW1zLgoKYGBge3IgcGxvdDh9CmNvcnJlY3RfcGlsb3RfZGF0YSA8LSBmaWx0ZXIocGlsb3RfZGF0YSwgQWNjdXJhY3kgPT0gMTAwKSAKCnBsb3R0ZXIoImNvcnJlY3RfcGlsb3RfZGF0YSIsICJSVCIsICJEaWZmaWN1bHR5IiwgIlJlc3BvbnNlIFRpbWUiLAogICAgICAgICJSYXRlZCBEaWZmaWN1bHR5IiwgMCwgNzUsIDAsIDExMCwgMTAsIDAsIDEwMCwgMTAsCiAgICAgICAgbGlzdChnZW9tX3BvaW50KHNpemUgPSAuNCkpKSArCiAgbGFicyhjYXB0aW9uID0gcGFzdGUoIkVhY2ggb2YgdGhlIiwKICAgICAgICAgICAgICAgICAgICAgICBucm93KGNvcnJlY3RfcGlsb3RfZGF0YSksCiAgICAgICAgICAgICAgICAgICAgICAgImRvdHMgcmVwcmVzZW50cyBvbmUgdHJpYWwgZm9yIG9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgInBhcnRpY2lwYW50XG4oZmlsdGVyZWQgZm9yIHRyaWFscyB3aXRoIFJUID4gNzUpIikpCmBgYAoKLS0tLQoKIyMjIENvcnJlbGF0aW9ucyBiZXR3ZWVuIFJlc3BvbnNlIFRpbWUsIFJhdGVkIERpZmZpY3VsdHksIGFuZCBBY2N1cmFjeSB7LX0KClRoZSBjb3JyZWxhdGlvbnMgZm9yIGFsbCBvZiB0aGVtIGFyZSBxdWl0ZSByb2J1c3QsIGVzcGVjaWFsbHkgZm9yIG11bHRpcGxpY2F0aW9uIHByb2JsZW1zCgpgYGB7ciBwbG90OX0KbGlzdCgKICAicGlsb3RfZGF0YV9zdW1tYXJpemVkIiwKICBjKCJSVCIsICJSVCIsICJBY2N1cmFjeSIpLAogIGMoIkRpZmZpY3VsdHkiLCAiQWNjdXJhY3kiLCAiRGlmZmljdWx0eSIpLAogIGMoIlJlc3BvbnNlIFRpbWUgKHNlY29uZHMpIiwgIlJlc3BvbnNlIFRpbWUgKHNlY29uZHMpIiwgIkFjY3VyYWN5ICglKSIpLAogIGMoIlJhdGVkIERpZmZpY3VsdHkiLCAiQWNjdXJhY3kgKCUpIiwgIlJhdGVkIERpZmZpY3VsdHkiKSwKICBjKDAsIDAsIDM1KSwKICBjKDMwLCAzMCwgMTAwKSwKICBjKDAsIDM1LCAwKSwKICBjKDc1LCAxMTAsIDc1KSwKICBjKDAsIDEwLCA2KSwKICBjKDAsIDMwLCAwKSwKICBjKDgwLCAxMDAsIDgwKSwKICAxMCwKICBsaXN0KGdlb21fcG9pbnQoc2l6ZSA9IDEpKQopICU+JQogIHBtYXAocGxvdHRlcikgJT4lCiAgcmVkdWNlKGArYCkgKwogIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlID0gIkF2ZXJhZ2VzIGZvciBFYWNoIENvbWJpbmF0aW9uIG9mIEFkZGVuZHMgYW5kIE11bHRpcGxpY2FuZHMiLAogICAgc3VidGl0bGUgPSBwYXN0ZSgiRWFjaCBvZiB0aGUiLAogICAgICAgICAgICAgICAgICAgIG5yb3cocGlsb3RfZGF0YV9zdW1tYXJpemVkKSwKICAgICAgICAgICAgICAgICAgICAiZG90cyBwZXIgZ3JhcGggcmVwcmVzZW50cyBvbmUgdHJpYWwiLAogICAgICAgICAgICAgICAgICAgICJhdmVyYWdlZCBhY3Jvc3Mgc3ViZ3JvdXBzIG9mIGFwcHJveGltYXRlbHkiLAogICAgICAgICAgICAgICAgICAgIHJvdW5kKG5fZGlzdGluY3QocGlsb3RfZGF0YSRTdWJfSUQpIC8gNCksCiAgICAgICAgICAgICAgICAgICAgInBhcnRpY2lwYW50c1xuIikpCmBgYAoKLS0tLQoKIyMgTm90YWJsZSBEaWZmcyBiL3cgTnVtYnIgQ21ib3Mgey19CgojIyMgTm8gQ2xlYXIgSW5mbGVjdGlvbiBQb2ludCBmb3IgTXVsdGlwbGljYXRpb24gRGlmZmljdWx0eSB7LX0KCldoZW4gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBtdWx0aXBsaWNhdGlvbiBhbmQgYWRkaXRpb24gcmVzcG9uc2UgdGltZSBhbW9uZyBjb3JyZWN0IHByb2JsZW1zIGlzIHBsb3R0ZWQgYWxvbmcgdGhlIHggYXhpcywgaW4gYXNjZW5kaW5nIG9yZGVyLCB0aGUgNTAlIG9uIHRoZSByaWdodCB2YXJ5IG1vcmUgdGhhbiB0aGUgNTAlIG9uIHRoZSBsZWZ0LCBzdWdnZXN0aW5nIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBpcyBza2V3ZWQgYnV0IG5vdCBzZWVtaW5nbHkgYmluYXJ5LiBUaGUgb3JhbmdlIGluZGljYXRlcyBob3cgbXVjaCBjaGFuZ2UgdGhlcmUgaXMgaW4gUlQgbW92aW5nIG9uZSB1bml0IGFsb25nIHRoZSB4IGF4aXMsIHVuZGVyc2NvcmluZyB0aGF0IHRoZXJlIGlzIG1vcmUgY2hhbmdlIGZ1cnRoZXIgYWxvbmcgcmlnaHQgYnV0IHRoZSBsYWNrIG9mIGFzIG11Y2ggY2hhbmdlIG5lYXIgdGhlIG1pZGRsZSBvZiB0aGUgZ3JhcGggcG9pbnRzIHRvIGEgcmVsYXRpdmVseSBjb250aW51b3VzIGRpc3RyaWJ1dGlvbiBhdCBsZWFzdCBtb3N0IG9mIHRoZSB3YXkgZ29pbmcgZnJvbSBsZWZ0IHRvIHJpZ2h0LiBUaGUgdG9wIHBsb3QganVzdCB0cmFuc2Zvcm1zIHRoZSBib3R0b20gZ3JhcGggc28gdGhhdCBlYWNoIHN0ZXAgaW4gdGhhdCAnaGlzdG9ncmFtJyBpcyBtb3Zpbmcgb25lIHNlY29uZCBpbiByZXNwb25zZSB0aW1lLiBTbyBhIGhpZ2ggYW5kIHdpZGUtc3Bhbm5pbmcgc3RlcCBtZWFucyB0aGF0IHRoZXJlIGFyZSBhIGxvdCBvZiBudW1iZXIgY29tYmluYXRpb25zIHdob3NlIG11bHRpcGxpY2F0aW9uIG1pbnVzIGFkZGl0aW9uIFJUIGRpZmZlcmVuY2UgaXMgYWxsIHdpdGhpbiBhIHNlY29uZCBvZiBlYWNoIG90aGVyLiBNb3JlIGNoYW5nZSBpbiB0aGlzIFJUIGRpZmZlcmVuY2UgZnJvbSBvbmUgY29tYmluYXRpb24gdG8gdGhlIG5leHQgbGVhZHMgdG8gc2hvcnRlciBhbmQgbmFycm93ZXIgc3RlcHMuCgpgYGB7ciwgcGxvdDEwfQpwbG90XzEwX2RhdGEgPC0gcGlsb3RfZGF0YSAlPiUKICBmaWx0ZXIoQWNjdXJhY3kgPT0gMTAwKSAlPiUKICBncm91cF9ieShMb3dfTnVtLCBIaWdoX051bSwgVGFzaykgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhSVCwgbWVhbikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWNyb3NzKFJULCB+LiAtIGxhZyguKSkpICU+JQogIGZpbHRlcihUYXNrID09ICJNdWx0aXBsaWNhdGlvbiIpICU+JQogIGFycmFuZ2UoUlQpICU+JQogIG11dGF0ZShDaGFuZ2UgPSBsZWFkKFJUKSAtIFJULAogICAgICAgICByb3dfcmFuayA9IDEwMCAqIHJvd19udW1iZXIoKSAvIG4oKSkKCnNtYWxsXzEwX3Bsb3QgPC0gcGxvdF8xMF9kYXRhJFJUICU+JSBtaW4gJT4lIGZsb29yCmJpZ18xMF9wbG90IDwtIHBsb3RfMTBfZGF0YSRSVCAlPiUgbWF4ICU+JSBjZWlsaW5nCnBsb3RfMTBfZGF0YV9leHBhbmRlZCA8LSBwbG90XzEwX2RhdGEgJT4lCiAgZXhwYW5kKG5lc3Rpbmcocm93X3JhbmssIENoYW5nZSksCiAgICAgICAgIFJUID0gZnVsbF9zZXEoYyhzbWFsbF8xMF9wbG90LCBiaWdfMTBfcGxvdCksIDEpKQoKKHBsb3RfMTBfZGF0YSAlPiUKICAgIGdyb3VwX2J5KGNlaWxpbmcoUlQpKSAlPiUKICAgIG11dGF0ZShHcm91cF9Db3VudCA9IG4oKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHJvd19yYW5rLCBHcm91cF9Db3VudCkpICsKICAgIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5Jywgd2lkdGg9MSwgZmlsbCA9ICJ3aGl0ZSIpICsKICAgIHBsb3RfMTBfdGhlbWUgKwogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MzIpKSArCiAgICB5bGFiKHBhc3RlKCJOdW1iZXIgb2YgQ29tYmluYXRpb25zIFdpdGhpbiAxIiwKICAgICAgICAgICAgICAgIlNlY29uZCBvZiBFYWNoIE90aGVyLCBwZXIgU2Vjb25kIiwgc2VwID0gIlxuIikpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiVGhlIFJlbGF0aXZlbHkgQ29udGludW91cyAodGhvdWdoIHNrZXdlZCkgRGlzdHJpYnV0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAiXG5vZiBNdWx0aXBsaWNhbmQgQ29tYmluYXRpb25zLGluIHRlcm1zIG9mIGVhc2luZXNzIikpKSAvCiAgCihnZ3Bsb3QocGxvdF8xMF9kYXRhLCBhZXMocm93X3JhbmssIFJUKSkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBwbG90XzEwX2RhdGFfZXhwYW5kZWQsCiAgICAgICAgICAgICAgYWVzKHJvd19yYW5rLCBSVCwgZmlsbCA9IENoYW5nZSksIGludGVycG9sYXRlID0gVFJVRSkgKwogIGdlb21fbGluZShhZXMoeD1yb3dfcmFuaywgUlQpLCBjb2xvcj0id2hpdGUiLHNpemU9MS41KSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93PSIjMWUzOTRhIiwgbWlkPSIjYmM2YzBkIiwgaGlnaD0iI2QyNjcwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAxLjEpICsKICBwbG90XzEwX3RoZW1lICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoc21hbGxfMTBfcGxvdCArIDEsIGJpZ18xMF9wbG90IC0xKSkgKwogICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDI1LCA3NSwgMjUpKSArCiAgIGxhYnMoeCA9IHBhc3RlKCJXaGVyZSBlYWNoIE11bHRpcGxpY2FuZCBDb21iaW5hdGlvbiBSYW5rcyBpbiBUZXJtcyBvZiIsCiAgICAgICAgICAgICAgICAgICJSZXNwb25zZSBUaW1lXG4oc29ydGVkIGluIGFzY2VuZGluZyBvcmRlcikiKSwKICAgICAgICB5ID0gIlJlc3BvbnNlIFRpbWVcbihTZWNvbmRzKSIpKQpgYGAKCi0tLS0KCiMjIyBNb3N0IGltcG9ydGFudCBncmFwaHMgey19CgpXZSd2ZSBhbHJlYWR5IGRpc2N1c3NlZCB0aGUgbGFzdCB0d28gZ3JhcGhzIHBsZW50eSwgc28gSSdsbCBqdXN0IGxlYXZlIHRoZW0gYmVsb3cgd2l0aG91dCBzYXlpbmcgYW55dGhpbmcgbW9yZS4KCmBgYHtyLCBwbG90MTF9Cmxpc3QoCiAgInBpbG90X2RhdGFfaGlnaF9udW1zIiwKICAiSGlnaF9OdW0iLAogIGMoIkFjY3VyYWN5IiwgIlJUIiwgIkRpZmZpY3VsdHkiKSwKICAiTGFyZ2VzdCBBZGRlbmQgb3IgTXVsdGlwbGljYW5kIiwKICBjKCJBY2N1cmFjeSAoJSkiLCAiUmVzcG9uc2UgVGltZSAoc2Vjb25kcykiLCAiUmF0ZWQgRGlmZmljdWx0eSIpLAogIDAsCiAgMjUsCiAgYyg2NSwgMCwgMCksCiAgYygxMDAsIDE1LCA1MCksCiAgNTAsCiAgYyg2MCwgMCwgMCksCiAgYygxMDAsIDE1LCA1MCksCiAgYygxMCwgMywgMTApLAogIGxpc3QoCiAgICBsaXN0KGdlb21fbGluZShzaXplID0gMSksIGdlb21fcG9pbnQoc2l6ZSA9IDIpKQogICkKKSAlPiUKICBwbWFwKHBsb3R0ZXIpICU+JQogIHJlZHVjZShgK2ApICsKICBwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcpICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiQXZlcmFnZXMgZm9yIExhcmdlc3QgQWRkZW5kIGFuZCBNdWx0aXBsaWNhbmQiLAogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlKCJFYWNoIHZhbHVlIGlzIGNvbGxhcHNlZCBhY3Jvc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9kaXN0aW5jdChwaWxvdF9kYXRhJFN1Yl9JRCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGFydGljaXBhbnRzXG4iKSkKYGBgCgotLS0tCgpgYGB7ciwgcGxvdDEyfQpsaXN0KAogIGMoIlJUIiwgIkFjY3VyYWN5IiwgIkRpZmZpY3VsdHkiKSwKICBjKCJSZXNwb25zZSBUaW1lIiwgIkFjY3VyYWN5IiwgIlJhdGVkIERpZmZpY3VsdHkiKSwKICBjKDAsIDQwLCAwKSwKICBjKDI1LCAxMDAsIDEwMCksCiAgYygwLCAxMDAsIDApLAogIGMoLTIsIC01MCwgLTEwKSwKICBjKDIwLCAxMCwgNjApLAogIDAsCiAgYygiIzBDNjI5MSIsICIjQTYzNDQ2IiwgIiMwQzYyOTEiKSwKICAiI0ZCRkVGOSIsCiAgYygiI0E2MzQ0NiIsICIjMEM2MjkxIiwgIiNBNjM0NDYiKQopICU+JQogIHBtYXAoaGVhdF9wbG90dGVyKSAlPiUKICByZWR1Y2UoYHxgKSArCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gcGFzdGUoIkFkZGl0aW9uIGFuZCBNdWx0aXBsaWNhdGlvbiBQcm9ibGVtcywgYW5kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGhlaXIgRGlmZmVyZW5jZSIpLAogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlKCJncm91cGVkLCBsZWZ0IHRvIHJpZ2h0LCBieSByZXNwb25zZSB0aW1lLCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImFjY3VyYWN5LCBhbmQgc2VsZi1yZXBvcnRlZCBkaWZmaWN1bHR5XG4iKSkKYGBgCgotLS0KCiMjIyBSIHNlc3Npb24gaW5mbyB7LX0KCmBgYHtyIHNlc3Npb24gaW5mbywgY29tbWVudD0iIn0KeGZ1bjo6c2Vzc2lvbl9pbmZvKCkKYGBgCgo=